
#include "putsDispose.h"

void trainTransfilePuts(int fd,int sockfd,MYSQL * mysql,char * real_file_path,char * real_prev_path,char * username,char * filepath,long sfilesize,long cfilesize){
    printf("transfile_enter\n");
    if(sfilesize == 0){              //如果文件是错的，那么就截断或拉长。防止服务器文件比客户机文件还大的情况。
        ftruncate(fd,cfilesize);
    }
    lseek(fd,sfilesize,SEEK_SET);
    Train train;
    while(1){
        int rret = recv(sockfd,&train.length,sizeof(train.length),MSG_WAITALL);
        if(rret == 0){
            printf("传输中断！\n");
            printf("into break;\n");
            lseek(fd,0,SEEK_SET);
            MD5_CTX ctx;
            MD5_Init(&ctx);
            char buff[4096];
            while(1){
                bzero(buff,sizeof(buff));
                ssize_t rret = read(fd,buff,sizeof(buff));
                if(rret == 0){
                    break;
                }              
                MD5_Update(&ctx,buff,rret);
            }
            unsigned char md[16];
            MD5_Final(md,&ctx);
            char md5_str_c[33] = {0};
            char num[3] = {0};
            for(int k =0 ; k < 16 ; ++k){
                sprintf(num,"%02x",md[k]);
                strcat(md5_str_c,num);
            }
            
            printf("已收到的文件的md5:%s\n",md5_str_c);
            char sql[1024] = {0};
            sprintf(sql,"update usrfile set md5 = '%s' where username = '%s' and path = '%s'",md5_str_c,username,filepath);
            int qret = mysql_query(mysql,sql);        
            if(qret != 0){
                fprintf(stderr,"mysql_query_train_puts :%s\n",mysql_error(mysql));
                return ;
            }
            
            char xiegang[] = "/";
            strcat(real_prev_path,xiegang);
            strcat(real_prev_path,md5_str_c);
            printf("旧的文件路径：%s,新的文件路径：%s\n",real_file_path,real_prev_path);
            rename(real_file_path,real_prev_path);
            printf("文件名字修改成功!\n");
            printf("out break\n");
            return;
        }
        if(train.length == 0){
            lseek(fd,0,SEEK_SET);
            MD5_CTX ctx;
            MD5_Init(&ctx);
            char buff[4096];
            while(1){
                bzero(buff,sizeof(buff));
                ssize_t rret = read(fd,buff,sizeof(buff));
                if(rret == 0){
                    break;
                }              
                MD5_Update(&ctx,buff,rret);
            }
            unsigned char md[16];
            MD5_Final(md,&ctx);
            char md5_str_c[33] = {0};
            char num[3] = {0};
            for(int k =0 ; k < 16 ; ++k){
                sprintf(num,"%02x",md[k]);
                strcat(md5_str_c,num);
            }
            
            printf("已收到的文件的md5:%s\n",md5_str_c);
            char sql[1024] = {0};
            sprintf(sql,"update usrfile set md5 = '%s' where username = '%s' and path = '%s'",md5_str_c,username,filepath);
            int qret = mysql_query(mysql,sql);        
            if(qret != 0){
                fprintf(stderr,"mysql_query_train_puts :%s\n",mysql_error(mysql));
                return ;
            }
            
            char xiegang[] = "/";
            strcat(real_prev_path,xiegang);
            strcat(real_prev_path,md5_str_c);
            printf("旧的文件路径：%s,新的文件路径：%s\n",real_file_path,real_prev_path);
            rename(real_file_path,real_prev_path);
            printf("文件名字修改成功!\n");
            
            printf("传输完成\n");
            break;
        }
        recv(sockfd,train.data,train.length,MSG_WAITALL);
        write(fd,train.data,train.length);
    }
    return;  
}


void mmapTransfilePuts(int fd,int sockfd,MYSQL * mysql,char * real_file_path,char * real_prev_path,char * username,char * filepath,long sfilesize,long cfilesize){
    printf("into mmap\n");
    char buf[4096] ;
    ftruncate(fd,sfilesize);
    lseek(fd,sfilesize,SEEK_SET);
    if(sfilesize!=0){
        printf("断点重传!\n");
    }
    long readedsize = sfilesize; 
    long remainsize = 0;
    int rret = 0;
    while(1){
        bzero(buf,sizeof(buf));
        remainsize = cfilesize - readedsize;
       if(remainsize > sizeof(buf)){
            rret = recv(sockfd,buf,sizeof(buf),MSG_WAITALL);
       }else{
            rret = recv(sockfd,buf,remainsize,MSG_WAITALL);
            write(fd,buf,rret);
            break;
       }
       if(rret == 0){
           printf("接收被中断！\n");
           printf("into break;\n");
           printf("计算已经收到的文件的md5值中.......\n");
           lseek(fd,0,SEEK_SET);
           MD5_CTX ctx;
           MD5_Init(&ctx);
           char buff[4096];
           while(1){
               bzero(buff,sizeof(buff));
               ssize_t rret = read(fd,buff,sizeof(buff));
               if(rret == 0){
                   break;
               }              
               MD5_Update(&ctx,buff,rret);
           }
           unsigned char md[16];
           MD5_Final(md,&ctx);
           char md5_str_c[33] = {0};
           char num[3] = {0};
           for(int k =0 ; k < 16 ; ++k){
               sprintf(num,"%02x",md[k]);
               strcat(md5_str_c,num);
           }
           printf("已经收到的文件的md5:%s\n",md5_str_c);
           char sql[1024] = {0};
           sprintf(sql,"update usrfile set md5 = '%s' where username = '%s' and path = '%s'",md5_str_c,username,filepath);
           int qret = mysql_query(mysql,sql);        
           if(qret != 0){
               fprintf(stderr,"mysql_query_train_puts :%s\n",mysql_error(mysql));
               return ;
           }

           char xiegang[] = "/";
           strcat(real_prev_path,xiegang);
           strcat(real_prev_path,md5_str_c);

           printf("旧的文件路径：%s,新的文件路径：%s\n",real_file_path,real_prev_path);
           rename(real_file_path,real_prev_path);
           printf("out break;\n");

           return ;

       }


       write(fd,buf,rret);
       readedsize = readedsize + rret;
    }
    printf("传输成功！\n");
    printf("out map\n");
    printf("计算收到文件的MD5值中......\n");    
    lseek(fd,0,SEEK_SET);
    MD5_CTX ctx;
    MD5_Init(&ctx);
    char buff[4096];
    while(1){
        bzero(buff,sizeof(buff));
        ssize_t rret = read(fd,buff,sizeof(buff));
        if(rret == 0){
            break;
        }              
        MD5_Update(&ctx,buff,rret);
    }
    unsigned char md[16];
    MD5_Final(md,&ctx);
    char md5_str_c[33] = {0};
    char num[3] = {0};
    for(int k =0 ; k < 16 ; ++k){
        sprintf(num,"%02x",md[k]);
        strcat(md5_str_c,num);
    }
    printf("已经收到的文件的md5:%s\n",md5_str_c);
    char sql[1024] = {0};
    sprintf(sql,"update usrfile set md5 = '%s' where username = '%s' and path = '%s'",md5_str_c,username,filepath);
    int qret = mysql_query(mysql,sql);        
    if(qret != 0){
        fprintf(stderr,"mysql_query_train_puts :%s\n",mysql_error(mysql));
        return ;
    }

    char xiegang[] = "/";
    strcat(real_prev_path,xiegang);
    strcat(real_prev_path,md5_str_c);

    printf("旧的文件路径：%s,新的文件路径：%s\n",real_file_path,real_prev_path);
    rename(real_file_path,real_prev_path);
    printf("文件重命名成功！\n");
    return ;
}



void putsDispose(int netfd,char * username,MYSQL * mysql,char * prev_path,char * real_path){

    char sql[1024] = {0};              //检查一下父结点是不是目录
    sprintf(sql,"select * from usrfile where username = '%s' and path = '%s' ;",username,prev_path);
    int qret = mysql_query(mysql,sql);
    if(qret != 0){
        fprintf(stderr,"mysql_query 1:%s\n",mysql_error(mysql));
        send(netfd,"0",1,MSG_NOSIGNAL);
        return ;
    }
    printf("1 over\n");
    MYSQL_RES * table = mysql_store_result(mysql);

    if(mysql_num_rows(table) == 0){
        send(netfd,"0",1,MSG_NOSIGNAL);
        return ;
    }

    MYSQL_ROW row1 = mysql_fetch_row(table);     //记录一下父节点

    if( strcmp(row1[5],"d") == 0){
        send(netfd,"1",1,MSG_NOSIGNAL);
    }else{
        send(netfd,"2",1,MSG_NOSIGNAL);
        return ;
    } 



    int epollfd = epoll_create(1);
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = netfd;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,netfd,&event);
    struct epoll_event readyset[5];
    epoll_wait(epollfd,readyset,5,-1);

    Train train;
    recv(readyset[0].data.fd,&train.length,sizeof(train.length),MSG_WAITALL);   //接收文件名字
    recv(readyset[0].data.fd,train.data,train.length,MSG_WAITALL);                                                                           
    char filename[128] = {0};
    memcpy(filename,train.data,train.length);
    printf("filename:%s\n",filename);

    recv(readyset[0].data.fd,&train.length,sizeof(train.length),MSG_WAITALL);   //接收客户端md5值
    recv(readyset[0].data.fd,train.data,train.length,MSG_WAITALL);
    char md5_str_c[33] = {0};
    memcpy(md5_str_c,train.data,train.length);

    printf("客户端md5:%s\n",md5_str_c);
    bzero(sql,sizeof(sql));                                                  //秒传逻辑
    sprintf(sql,"select * from usrfile where md5 = '%s' ;",md5_str_c);
    qret = mysql_query(mysql,sql);
    if(qret != 0){
        fprintf(stderr,"mysql_query 2:%s\n",mysql_error(mysql));
        return ;
    }
    printf("2 over\n");
    table = mysql_store_result(mysql);
    
    if(mysql_num_rows(table) == 0){
        send(netfd,"0",1,MSG_NOSIGNAL);
    }else{
        bzero(sql,sizeof(sql));
        char ass_filename[128] = {0};
        memcpy(ass_filename,filename,strlen(filename));
        if(strcmp(prev_path,"/") != 0){
            char aaaa[] = "/";
            strcat(prev_path,aaaa);
        }
        strcat(prev_path,ass_filename);    //拼出当前文件的路径
        printf("1当前文件路径为：%s\n",prev_path);
        sprintf(sql,"select * from usrfile where username = '%s' and path = '%s' ;",username,prev_path);   //查询有没有这个文件表项
        qret = mysql_query(mysql,sql);
        if(qret != 0){
            fprintf(stderr,"mysql_query 3:%s\n",mysql_error(mysql));
            return ;
        }
        printf("3 over\n");
        MYSQL_RES * table = mysql_store_result(mysql);
        if(mysql_num_rows(table) != 0){                     //原来就有这个表项。说明是个重名文件或者是中断传输的文件
            MYSQL_ROW row2 = mysql_fetch_row(table);       
            if( strcmp(row2[6],md5_str_c) != 0 ){            //规定：文件的md5值一定存在。所以只要检测一不一样就可以
                    bzero(sql,sizeof(sql));
                    sprintf(sql,"update usrfile set md5 = '%s' where username = '%s' and path = '%s' ;",md5_str_c,username,prev_path);
                    qret = mysql_query(mysql,sql);
                    if(qret != 0){
                        fprintf(stderr,"mysql_query 4:%s\n",mysql_error(mysql));
                        return ;
                    }

                    printf("4 over\n");
                printf("update table success\n");
            }
        }else{                  //原来没有这个表项。那我们新插入一个表项
            bzero(sql,sizeof(sql));
            sprintf(sql,"insert into usrfile (filename,username,parent_id,path,type,md5) values ('%s','%s',%s,'%s','%c','%s') ;",filename,username,row1[0],prev_path,'f',md5_str_c);
            qret = mysql_query(mysql,sql);
            if(qret != 0){
                fprintf(stderr,"mysql_query 5:%s\n",mysql_error(mysql));
                return ;
            }
            printf("insert table succuss!\n");
        }
        printf("flash transfile success!\n");
        send(netfd,"1",1,MSG_NOSIGNAL);    //改完表项，秒传成功！
        return ;
    }
    
    //退化到一二期的断点重传
    epoll_wait(epollfd,readyset,5,-1);

    recv(readyset[0].data.fd,&train.length,sizeof(train.length),MSG_WAITALL);   //接收客户端文件大小
    recv(readyset[0].data.fd,train.data,train.length,MSG_WAITALL);
    long filesize = 0; 
    memcpy(&filesize,train.data,train.length);
    printf("收到client filesize:%ld\n",filesize);
    
    char isBig;                                             // 接收是否是大文件
    recv(readyset[0].data.fd,&isBig,1,MSG_WAITALL);    
    printf("isBig:%c\n",isBig);
    
    char ass_filename[128] = {0};        //strcat 会改掉第二个参数，所以我们搞个文件名副本
    memcpy(ass_filename,filename,strlen(filename));
   if(strcmp(prev_path,"/") != 0){
     char bbbb[] = "/";
     strcat(prev_path,bbbb);
   }
    strcat(prev_path,ass_filename);      //拼接文件名，得到文件路径
    printf("2当前文件路径为：%s\n",prev_path);
    printf("321321313123%s,%s\n",username,prev_path);
    bzero(sql,sizeof(sql));
    sprintf(sql,"select * from usrfile where username = '%s' and path = '%s' ;",username,prev_path);   //查询有没有这个文件表项
    
    qret = mysql_query(mysql,sql);
    if(qret != 0){
        fprintf(stderr,"mysql_query 6:%s\n",mysql_error(mysql));
        return ;
    }
    printf("6 over\n");
    table = mysql_store_result(mysql);
    int aaa = mysql_num_rows(table);
   
    if(aaa == 0){         //表中没有,没传过。
        send(netfd,"0",1,MSG_NOSIGNAL);
        bzero(sql,sizeof(sql));
        printf("prev_path :%s\n",prev_path);
        sprintf(sql,"insert into usrfile (filename,username,parent_id,path,type,md5) values ('%s','%s',%s,'%s','%c','%s') ;",filename,username,row1[0],prev_path,'f',"default");
        qret = mysql_query(mysql,sql);
        if(qret != 0){
            fprintf(stderr,"mysql_query 7:%s\n",mysql_error(mysql));
            return ;
        }
        printf("7 over\n");
        
        char default_name[] = "default";
        char ccccc[] = "/";
        char real_file_path[1024] = {0};
        memcpy(real_file_path,real_path,strlen(real_path));
        strcat(real_file_path,ccccc);
        strcat(real_file_path,default_name);
        
        epoll_wait(epollfd,readyset,5,-1);
        
        int fd = open(real_file_path,O_RDWR|O_CREAT|O_TRUNC,0777);    //在当前文件夹下创建文件
        if(isBig == '0'){
            printf("fd:%d\n",fd);
            printf("readyset[0].data.fd:%d\n",readyset[0].data.fd);
            printf("real_file_path:%s\n",real_file_path);
            printf("real_path:%s\n",real_path);
            printf("username:%s\n",username);
            printf("prev_path:%s\n",prev_path);
            printf("filesize:%ld\n",filesize);
            trainTransfilePuts(fd, readyset[0].data.fd ,mysql, real_file_path , real_path , username,prev_path, 0 ,filesize);
        }
        if(isBig == '1'){
            printf("fd:%d\n",fd);
            printf("readyset[0].data.fd:%d\n",readyset[0].data.fd);
            printf("real_file_path:%s\n",real_file_path);
            printf("real_path:%s\n",real_path);
            printf("username:%s\n",username);
            printf("prev_path:%s\n",prev_path);
            printf("filesize:%ld\n",filesize);
            mmapTransfilePuts(fd, readyset[0].data.fd ,mysql,real_file_path, real_path, username, prev_path, 0, filesize);

        }
        return ;
    }
    MYSQL_ROW row3 = mysql_fetch_row(table);
    if(strcmp(row3[5],"d") == 0){                   //但是是目录文件
        send(netfd,"2",1,MSG_NOSIGNAL);
        return ;
    }
    send(netfd,"1",1,MSG_NOSIGNAL);            //发送"有"信号
    //只需把文件名拼上
    char real_filename[1024] = {0};
    char real_file_path[1024] = {0};
    memcpy(real_filename,row3[6],strlen(row3[6]));
    memcpy(real_file_path,real_path,strlen(real_path));
    char cccc[] = "/";
    strcat(real_file_path,cccc);
    strcat(real_file_path,real_filename);
    printf("real_file_path:%s\n",real_file_path);

    int fd = open(real_file_path,O_RDWR);          //打开文件

    struct stat statbuf;
    fstat(fd,&statbuf);
    train.length = sizeof(statbuf.st_size);
    memcpy(train.data,&statbuf.st_size,train.length);
    send(netfd ,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);   //发送服务端文件长度

    printf("server md5:%s\n",row3[6]);
    train.length = strlen(row3[6]);
    memcpy(train.data,row3[6],train.length);
    send(netfd,&train,sizeof(train.length)+train.length,MSG_NOSIGNAL);


    epoll_wait(epollfd,readyset,5,-1);    //等客户端确认是哪种重传
    char buf[1024];
    bzero(buf,sizeof(buf));            
    recv(readyset[0].data.fd,buf,2,MSG_WAITALL);

   
    if(strcmp(buf,"1") == 0){     //是同一个文件。
        printf("是同一个文件\n");
        if(isBig == '1'){
            printf("进入mmap\n");
            printf("fd:%d\n",fd);
            printf("readyset[0].data.fd:%d\n",readyset[0].data.fd);
            printf("real_file_path:%s\n",real_file_path);
            printf("real_path:%s\n",real_path);
            printf("username:%s\n",username);
            printf("row3[4]:%s\n",row3[4]);
            printf("filesize:%ld\n",filesize);
            mmapTransfilePuts(fd,readyset[0].data.fd,mysql,real_file_path,real_path,username,row3[4],statbuf.st_size,filesize);   //文件描述符，套接字，服务器文件大小，客户机文件大小
        }
        if(isBig == '0'){
            printf("进入train\n");
            printf("fd:%d\n",fd);
            printf("readyset[0].data.fd:%d\n",readyset[0].data.fd);
            printf("real_file_path:%s\n",real_file_path);
            printf("real_path:%s\n",real_path);
            printf("username:%s\n",username);
            printf("row3[4]:%s\n",row3[4]);
            printf("filesize:%ld\n",filesize);
            trainTransfilePuts(fd,readyset[0].data.fd,mysql,real_file_path,real_path,username,row3[4] ,statbuf.st_size,filesize);    // 文件描述符，套接字，服务器文件大小,客户机文件大小
        }
    }
    if(strcmp(buf,"0") == 0){    //不是同一个文件
        printf("不是同一个文件\n");
        if(isBig == '1'){
            printf("进入mmap\n");
            printf("fd:%d\n",fd);
            printf("readyset[0].data.fd:%d\n",readyset[0].data.fd);
            printf("real_file_path:%s\n",real_file_path);
            printf("real_path:%s\n",real_path);
            printf("username:%s\n",username);
            printf("row3[4]:%s\n",row3[4]);
            printf("filesize:%ld\n",filesize);
            mmapTransfilePuts(fd,readyset[0].data.fd,mysql,real_file_path,real_path,username,row3[4],0,filesize);    
        }
        if(isBig == '0'){
            printf("进入train\n");
            printf("fd:%d\n",fd);
            printf("readyset[0].data.fd:%d\n",readyset[0].data.fd);
            printf("real_file_path:%s\n",real_file_path);
            printf("real_path:%s\n",real_path);
            printf("username:%s\n",username);
            printf("row3[4]:%s\n",row3[4]);
            printf("filesize:%ld\n",filesize);
            trainTransfilePuts(fd,readyset[0].data.fd,mysql,real_file_path,real_path,username,row3[4],0,filesize);
        }
    }

    return ;
}




